/*
 * COPYRIGHT. ShenZhen JiMi Technology Co., Ltd. 2017.
 * ALL RIGHTS RESERVED.
 *
 * No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
 * on any form or by any means, electronic, mechanical, photocopying, recording, 
 * or otherwise, without the prior written permission of ShenZhen JiMi Network Technology Co., Ltd.
 *
 * Amendment History:
 * 
 * Date                   By              Description
 * -------------------    -----------     -------------------------------------------
 * 2017年4月14日    li.shangzhi         Create the class
 * http://www.jimilab.com/
 */

package com.jimi.web.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;

import com.alibaba.fastjson.JSONObject;
import com.jimi.framework.context.SpringContextHolder;
import com.jimi.web.comm.DeviceLocationInfo;
import com.jimi.web.comm.DeviceType;
import com.jimi.web.comm.GPSProtocol;
import com.jimi.web.comm.HBProtocol;
import com.jimi.web.model.Device;
import com.jimi.web.model.DeviceLoginInfo;
import com.jimi.web.util.map.CoordinateConversion;
import com.jimi.web.util.map.Point;

/**
 * @FileName DeviceUtil.java
 * @Description:
 *
 * @Date 2017年4月14日 上午11:23:34
 * @author li.shangzhi
 * @version 1.0
 */
public class DeviceUtil {

	private static final Logger logger = LoggerFactory.getLogger(DeviceUtil.class);

	private static RedisTemplate<String, String> redisTemplate = SpringContextHolder.getBean("tuqiangRedisTemplate");

	// 10号索引的redis模板
	private static RedisTemplate<String, String> tuqiangCmdRedisTemplate = SpringContextHolder.getBean("tuqiangCmdRedisTemplate");

	// static {
	// redisTemplate.getConnectionFactory().getConnection().select(10);
	// }

	/**
	 * @Title: getDeviceLocationInfo
	 * @Description: 获取多个设备的定位信息
	 * @param deviceList
	 *            设备集合
	 * @param mapType
	 *            地图类型(BAIDU/GOOGLE)，默认百度坐标
	 * @return
	 * @author li.shangzhi
	 * @date 2017年4月14日 上午11:25:09
	 */
	public static List<DeviceLocationInfo> getDeviceLocationInfo(List<Device> deviceList, String mapType, String language) {
		if (null == deviceList || deviceList.isEmpty()) {
			return Collections.emptyList();
		}
		List<DeviceLocationInfo> dataList = new ArrayList<>();

		Set<String> imeis = new HashSet<>();
		for (Device device : deviceList) {
			imeis.add(device.getImei());
		}
		// 批量获取心跳包
		Map<String, HBProtocol> hbMap = getHbMap(imeis);
		// 批量获取GPS包
		Map<String, GPSProtocol> gpsMap = getGpsMap(imeis);

		for (Device device : deviceList) {
			HBProtocol hb = hbMap.get(device.getImei());
			GPSProtocol gps = gpsMap.get(device.getImei());
			DeviceLocationInfo locationInfo = getDeviceLocationInfo(device, hb, gps, mapType, language);
			dataList.add(locationInfo);
		}

		return dataList;
	}

	/**
	 * @Title: getDeviceLocationInfo
	 * @Description: 获取单个设备的定位信息
	 * @param device
	 *            设备信息
	 * @param hb
	 *            心跳信息
	 * @param gps
	 *            定位信息
	 * @param mapType
	 *            地图类型(BAIDU/GOOGLE)，为空时时原始坐标
	 * @return
	 * @author li.shangzhi
	 * @date 2017年4月14日 上午11:41:14
	 */
	public static DeviceLocationInfo getDeviceLocationInfo(Device device, HBProtocol hb, GPSProtocol gps, String mapType, String language) {
		if (null == device) {
			return null;
		}
		DeviceLocationInfo locationInfo = new DeviceLocationInfo();
		locationInfo.setImei(device.getImei());
		locationInfo.setDeviceName(getDeviceName(device));
		locationInfo.setMcType(device.getMcType());
		locationInfo.setMcTypeUseScope(device.getMcTypeUseScope());
		locationInfo.setIcon(device.getVehicleIcon());
		if (StringUtils.isBlank(device.getVehicleIcon())) {
			locationInfo.setIcon("other");
		}

		int status = getStatus(hb);
		locationInfo.setStatus(String.valueOf(status));

		Long millisecond = getIdelMillisecond(device.getImei(), status, hb, gps);
		locationInfo.setIdelTiem(millisecond == null ? "" : String.valueOf(millisecond));

		if (status == 0) {
			locationInfo.setAccStatus("0");
		}

		if (null != hb) {
			logger.info("imei:{}，心跳信息：{}", device.getImei(), JSONObject.toJSONString(hb));
			locationInfo.setHbTime(hb.getTime());
			locationInfo.setAccStatus(hb.getAccStatus());
			locationInfo.setGpsSignal(hb.getgPSSignal());
			locationInfo.setPowerLevel(hb.getPowerLevel());
			locationInfo.setPowerValue(hb.getPowerValue());
			locationInfo.setBatteryPowerVal(hb.getBatteryPowerVal());
			locationInfo.setFortifyStatus(hb.getFortifyStatus());
			locationInfo.setOilEleStatus(hb.getOilEleStatus());

			// 电量
			locationInfo.setElectQuantity(DeviceType.ElecQuantityMcType.getElecQuantity(device.getMcType(), hb));
		} else {
			logger.info("imei:{}，没有心跳信息。", device.getImei());
		}

		if (null != gps) {
			logger.info("imei:{}，GSP信息：{}", device.getImei(), JSONObject.toJSONString(gps));

			Point point = new Point();
			point.setLat(gps.getLatitude());
			point.setLng(gps.getLongitude());
			point = transformPoint(point, mapType, language);
			
			locationInfo.setLat(point.getLat());
			locationInfo.setLng(point.getLng());

			locationInfo.setGpsNum("-1".equals(gps.getGpsInfo()) ? "0" : gps.getGpsInfo());

			locationInfo.setGpsMode(gps.getGpsMode());
			locationInfo.setSpeed(gps.getGpsSpeed());
			locationInfo.setDirection(gps.getDirection());

			if (GPSProtocol.PosType.GPS.getValue().equals(gps.getPosType())) {
				locationInfo.setGpsTime(gps.getGpsTime());
			} else {
				locationInfo.setGpsTime(gps.getOtherPosTime());
			}

			if (StringUtils.isBlank(gps.getPosType())) {
				locationInfo.setPosType("GPS");
			} else {
				locationInfo.setPosType(gps.getPosType());
			}
			locationInfo.setLocDesc(gps.getLocDesc());
		} else {
			logger.info("imei:{}，没有GPS信息。", device.getImei());
		}
		// 是否有行程
		if (DeviceType.NoTripMcType.ifExis(device.getMcType().toUpperCase())) {
			locationInfo.setTripFlag("1");
		} else {
			locationInfo.setTripFlag("0");
		}
		// 是否支持录音
		if (DeviceType.Record.ifExis(device.getMcType())) {
			locationInfo.setRecordFlag("1");
		} else {
			locationInfo.setRecordFlag("0");
		}
		// 是否激活
		if (null != device.getActivationTime()) {
			locationInfo.setActivationFlag("1");
		} else {
			locationInfo.setActivationFlag("0");
		}
		// 是否过期
		Date expiration = device.getExpiration();
		if (expiration != null && expiration.getTime() > new Date().getTime()) {
			locationInfo.setExpireFlag("1");
		} else {
			locationInfo.setExpireFlag("0");
		}
		// 是否绑定
		if (StringUtils.isNotBlank(device.getBindUserId())) {
			locationInfo.setIsBind("1");
		} else {
			locationInfo.setIsBind("0");
		}
		// 是否需要设置时间
		if (DeviceType.SetTimeMcType.ifSetTime(device.getMcType())) {
			locationInfo.setIsSetTime("1");
		} else {
			locationInfo.setIsSetTime("0");
		}

		return locationInfo;
	}

	/**
	 * @Title: transformPoint
	 * @Description: 原始坐标转换指定类型
	 * @param point
	 *            坐标对象
	 * @param mapType
	 *            地图类型
	 * @param language
	 *            语言
	 * @return
	 * @author li.shangzhi
	 * @date 2017年8月16日 下午4:56:27
	 */
	private static Point transformPoint(Point point, String mapType, String language) {
		if ("BAIDU".equals(mapType)) {
			// 将原始gps装换成百度坐标
			return CoordinateConversion.gpsToBaidu(point);
		} else if ("GOOGLE".equals(mapType)) {
			if ("zh".equals(language)) {
				// 国内，原始坐标转成gcj-02
				return CoordinateConversion.wgs_gcj_encrypts_bak(point.getLat(), point.getLng());
			} else {
				// 国外，返回原始gps坐标
				return point;
			}
		} else {
			// 地图类型为空，或其他值，返回原始gps坐标
			return point;
		}
	}

	/**
	 * @Title: getIdelMillisecond
	 * @Description: 离线静止时间计算
	 * @param imei
	 * @param status
	 * @param hb
	 * @param gps
	 * @return
	 * @author li.shangzhi
	 * @date 2017年4月14日 下午2:13:53
	 */
	public static Long getIdelMillisecond(String imei, int status, HBProtocol hb, GPSProtocol gps) {
		if (status == 0) {// 离线时间
			if (hb != null && hb.getTime() != null) {
				return System.currentTimeMillis() - hb.getTime().getTime();
			}
		}
		if (status == 1) {// 静止时间
			Date d = null;
			if (null != gps) {
				d = gps.getGpsTime();
			} else {
				BoundHashOperations<String, String, String> boundHashOperations = redisTemplate
						.boundHashOps(RedisGlobals.DC_DEVICE_LOGININFO);
				String loginInfoJson = boundHashOperations.get(imei);
				if (StringUtils.isNotBlank(loginInfoJson)) {
					DeviceLoginInfo deviceLoginInfo = JSONObject.parseObject(loginInfoJson, DeviceLoginInfo.class);
					d = deviceLoginInfo.getFirstTime();
				}
			}
			if (d != null) {
				return System.currentTimeMillis() - d.getTime();
			}
		}
		return null;
	}

	/**
	 * @Title: getHBProtocol
	 * @Description: 获取心跳信息
	 * @param imei
	 * @return
	 * @author li.shangzhi
	 * @date 2017年4月14日 下午1:54:05
	 */
	public static HBProtocol getHBProtocol(String imei) {
		BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps(RedisGlobals.TRACKER_HB);
		String hbjson = boundHashOperations.get(imei);
		if (StringUtils.isNotBlank(hbjson)) {
			return JSONObject.parseObject(hbjson, HBProtocol.class);
		}
		return null;
	}

	/**
	 * @Title: getHbMap
	 * @Description: 获取设备心跳信息
	 * @param imeiArray
	 *            imei列表
	 * @return Map<imei,HBProtocol>
	 * @author li.shangzhi
	 * @date 2017年4月14日 上午11:49:30
	 */
	private static Map<String, HBProtocol> getHbMap(Set<String> imeiArray) {
		BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps(RedisGlobals.TRACKER_HB);
		List<String> hbList = boundHashOperations.multiGet(imeiArray);
		Map<String, HBProtocol> hbMap = new HashMap<>();
		if (null != hbList && hbList.size() > 0) {
			for (String data : hbList) {
				if (StringUtils.isNotBlank(data)) {
					HBProtocol hb = JSONObject.parseObject(data, HBProtocol.class);
					hbMap.put(hb.getDeviceImei(), hb);
				}
			}
		}
		return hbMap;
	}

	/**
	 * @Title: getGPSProtocol
	 * @Description: 获取定位信息
	 * @param imei
	 * @return
	 * @author li.shangzhi
	 * @date 2017年4月14日 下午1:54:16
	 */
	public static GPSProtocol getGPSProtocol(String imei) {
		BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps(RedisGlobals.TRACKER_GPS);
		String gpsjson = boundHashOperations.get(imei);
		if (StringUtils.isNotBlank(gpsjson)) {
			return JSONObject.parseObject(gpsjson, GPSProtocol.class);
		}
		return null;
	}

	/**
	 * @Title: getGpsMap
	 * @Description: 获取定位信息
	 * @param imeiArray
	 * @return
	 * @author li.shangzhi
	 * @date 2017年4月14日 下午1:54:25
	 */
	private static Map<String, GPSProtocol> getGpsMap(Set<String> imeiArray) {
		BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps(RedisGlobals.TRACKER_GPS);
		List<String> gpsList = boundHashOperations.multiGet(imeiArray);
		Map<String, GPSProtocol> gpsMap = new HashMap<>();
		if (null != gpsList && gpsList.size() > 0) {
			for (String data : gpsList) {
				if (StringUtils.isNotBlank(data)) {
					GPSProtocol gps = JSONObject.parseObject(data, GPSProtocol.class);
					gpsMap.put(gps.getDeviceImei(), gps);
				}
			}
		}
		return gpsMap;
	}

	/**
	 * 获取设备名称
	 */
	private static String getDeviceName(Device device) {
		if (StringUtils.isNotBlank(device.getDeviceName())) {
			return device.getDeviceName();
		}

		String imei = device.getImei();
		String mcType = device.getMcType();
		int length = imei.length();
		if (StringUtils.isNotBlank(mcType) && StringUtils.isNotBlank(imei)) {
			return mcType + "-" + imei.substring(length - 5, length);
		} else {
			return imei;
		}
	}

	/**
	 * @Title: getStatus
	 * @Description: 获取设备状态
	 * @param hbProtocol
	 * @return
	 * @author li.shangzhi
	 * @date 2017年4月14日 下午2:04:37
	 */
	private static int getStatus(HBProtocol hbProtocol) {
		int status = 0;
		if (null == hbProtocol) {
			return status;
		}
		if (null != hbProtocol && hbProtocol.getTime() != null) {
			long endTime = new Date().getTime();
			long start = hbProtocol.getTime().getTime();
			long count = endTime - start;
			// 7分钟判断是否在线 5*60*1000
			if (count > 7 * 60 * 1000) {
				// 0,离线; 1,在线
				status = 0;
			} else {
				// 0,离线; 1,在线
				status = 1;
			}
		}
		// 0,离线; 1,在线
		return status;
	}

	/**
	 * @Title: saveOfflineInstToRedis
	 * @Description: 保存离线指令到redis中，等待设备上线时处理
	 * @param imei
	 *            设备imei
	 * @param content
	 *            指令内容
	 * @param logId
	 *            日志id
	 * @param protocol
	 *            协议号
	 * @author li.shangzhi
	 * @date 2017年7月26日 下午2:50:38
	 */
	public static void saveOfflineInstToRedis(String imei, String content, Integer logId, Integer protocol) {
		JSONObject cmdJson = new JSONObject();
		cmdJson.put("_content", content);
		cmdJson.put("_serverFlagId", logId);
		cmdJson.put("_protocol", protocol);
		cmdJson.put("_language", "zh");
		cmdJson.put("_batchInsType", "simple");
		cmdJson.put("_paramIds", "");// 开放API调用没有参数id
		BoundHashOperations<String, String, String> boundHashOperations = tuqiangCmdRedisTemplate.boundHashOps(imei);
		boundHashOperations.put(Globals.InstructionCode.NORMAL_INS, cmdJson.toJSONString());
	}
}
